
#include "MonsterRefMgr.h"
#include "MonsterRefCfg.h"
#include "MonsterMgr.h"
#include "Common/TableDataEx/DeputyCfg.h"
#include "Common/TableData/NpcNpcCfg.h"
#include "Common/TableData/BattlenpcBattlenpcCfg.h"
#include "Common/Utility/ServerTime.h"
#include "Character/npc/Npc.h"
#include "Character/npc/NpcMgr.h"
#include "Character/object/ObjectMgr.h"
#include "Character/CreatureMgr.h"
#include "base/core/Profiler.h"
#include "base/core/gamemath.h"

SceneGenenalCreatureRef::SceneGenenalCreatureRef(uint32_t sceneId)
{
	m_sceneId = sceneId;
}

SceneGenenalCreatureRef::~SceneGenenalCreatureRef()
{

}

bool SceneGenenalCreatureRef::Init()
{
	return true;
}

bool SceneGenenalCreatureRef::UnInit()
{
	UnInitMonsterRef();
	UnInitNpcRef();
	UnInitCollectRef();
	return true;
}

bool SceneGenenalCreatureRef::InitMonsterRef(uint32_t mapId, uint32_t sceneId)
{
	MapLoactionCfg::MonsterRefLocationMap* pMonsterRef = g_GetMapLocationCfg()->getMonsterRefMap(mapId);
	if (pMonsterRef == nullptr)
	{
		return true;
		//return false;
	}

	MapLoactionCfg::MonsterRefLocationMap::iterator it = pMonsterRef->begin();
	for (; it != pMonsterRef->end(); it++)
	{
		std::vector<MonsterRefLocation>& vec = it->second;

		MonsterRefLocation loc;
		Monster* pMonster = nullptr;

		for (size_t i = 0; i < vec.size(); i++)
		{
			if (vec[i].m_fresh == 1) //是否一开始就刷出来
			{
				Point3<float> curDir = Point3<float>(0,0,1);
				if (vec[i].m_dir != Point3<float>())
				{
					float rad = AngleToRadian(vec[i].m_dir.y);
					float x = sin(rad);
					float z = cos(rad);
					Point3<float> dir = Point3<float>(x,0, z);
					float length = dir.length();
					if (length != 0)
					{
						curDir = dir/ length;
					}
				}
				MonsCreateParam createParam;
				createParam.createType = EMonsCreateType_Map;
				createParam.createTypeVal = mapId;
				pMonster = g_GetCreatureMgr()->CreateMonster(vec[i].m_id, sceneId, vec[i].m_bornPos, createParam, curDir, vec[i].m_RefLocIndex, nullptr, 0, vec[i].m_group);
				if (pMonster)
				{
					pMonster->SetFormationId(vec[i].m_group);
					pMonster->SetModelScale(vec[i].m_scale);
					if (vec[i].m_scale == Point3<float>())
					{
						//LogErrFmtPrint("monster:%d  scale = Point3<float>(0,0,0)...", vec[i].m_id);
					}
					//死亡时间大于0的才有刷新，跟编队没关系
					if (/*vec[i].m_group == 0 &&*/ vec[i].m_internalTime != 0)
					{
						loc = vec[i];
						loc.m_deadTime = 0;
						m_curMonsterCids.insert(std::make_pair(pMonster->GetCid(), loc));
					}
				}
				else
				{
					LogErrFmtPrint("the refresh scene:%d create monster failed", sceneId);
				}
			}
		}
	}
	return true;
}

bool SceneGenenalCreatureRef::UnInitMonsterRef()
{
	m_curMonsterCids.clear();
	m_deadMonsterCids.clear();
	return true;
}

bool SceneGenenalCreatureRef::InitNpcRef(uint32_t mapId, uint32_t sceneId)
{
	std::vector<NPCRefLocation>* pVec = g_GetMapLocationCfg()->getNPCRefLoc(mapId);
	if (pVec == nullptr)
	{
		return false;
	}

	std::vector<NPCRefLocation>& vec = *pVec;
	size_t i = 0;
	NPCRefLocation loc;
	Npc *pNpc = nullptr;

	for (; i < vec.size(); i++)
	{
		loc = vec[i];
		pNpc = g_GetCreatureMgr()->CreateNpc(loc.m_id, sceneId, loc.m_bornPos,loc.m_RefLocIndex);
		if (pNpc)
		{
			if (loc.m_internalTime > 0) //有复活时间的才需要记录
			{
				m_curNpcCids.insert(std::make_pair(pNpc->GetCid(), loc));
			}			
		}
		else
		{
			LogErrFmtPrint("the refresh scene:%d create npc failed:npcId:%d", sceneId, loc.m_id);
		}
	}
	return true;

}

bool SceneGenenalCreatureRef::UnInitNpcRef()
{
	m_curNpcCids.clear();
	return true;
}


bool SceneGenenalCreatureRef::InitCollectRef(uint32_t mapId, uint32_t sceneId)
{
	const MapThingCollectByTypeCfg *pCollectByTypeCfg = g_GetDeputyCfgMgr()->GetMapThingCollectCfg(mapId);
	if (nullptr != pCollectByTypeCfg)
	{
		MapThingCollectByTypeCfg::const_iterator iter = pCollectByTypeCfg->begin();
		for (; iter != pCollectByTypeCfg->end(); ++iter)
		{
			if (CollectData_Type_Peel == iter->first)
				continue;
			g_GetObjectMgr()->InitSceneObject(iter->second, mapId, sceneId);
		}
	}

	return true;
}

bool SceneGenenalCreatureRef::UnInitCollectRef()
{
	return true;
}

void SceneGenenalCreatureRef::npcDead(CharIDType npcCid)
{
	mapNpcIdToRefLocation::iterator it = m_curNpcCids.find(npcCid);
	if (it == m_curNpcCids.end())
	{
		return;
	}

	NPCRefLocation loc = it->second;
	loc.m_deadTime = g_GetGlobalServerTime()->Tick();

	const NpcNpcCfgInfo *m_npcCfgInfo = g_GetNpcNpcCfgTable()->GetNpcNpcCfgInfo(loc.m_id);
	if (m_npcCfgInfo)
	{
		const BattlenpcBattlenpcCfgInfo *pBattleInfo = g_GetBattlenpcBattlenpcCfgTable()->GetBattlenpcBattlenpcCfgInfo(m_npcCfgInfo->linkBattlenpc);
		if (pBattleInfo && pBattleInfo->npcTeam > 0)
		{
			m_deadNpcTeamCids[pBattleInfo->npcTeam].insert(std::make_pair(npcCid, loc));
			m_curNpcCids.erase(npcCid);

			auto pTeam = g_GetCreatureMgr()->GetNpcTeam(m_sceneId, pBattleInfo->npcTeam);
			if (pTeam->empty())
			{
				UpdateNpcTeam(m_sceneId, g_GetGlobalServerTime()->Tick(), pBattleInfo->npcTeam);
			}
			return;
		}
	}

	m_deadNpcCids.insert(std::make_pair(npcCid, loc));
	m_curNpcCids.erase(npcCid);

	//LogDebugFmtPrint("the monster:%d dead", monsterCid);
}

void SceneGenenalCreatureRef::monsterDead(CharIDType monsterCid)
{
	mapMonsterIdToRefLocation::iterator it = m_curMonsterCids.find(monsterCid);
	if (it == m_curMonsterCids.end())
	{
		return;
	}

	MonsterRefLocation loc = it->second;
	loc.m_deadTime = g_GetGlobalServerTime()->Tick();

	m_deadMonsterCids.insert(std::make_pair(monsterCid, loc));
	m_curMonsterCids.erase(monsterCid);

	//LogDebugFmtPrint("the monster:%d dead", monsterCid);
}

void SceneGenenalCreatureRef::UpdateNpcTeam(uint32_t sceneId, uint64_t tick, uint32_t npcTeamId)
{
	Npc* pNpc = nullptr;
	auto iter = m_deadNpcTeamCids.find(npcTeamId);
	if (iter == m_deadNpcTeamCids.end()) return;

	mapNpcIdToRefLocation& ref = iter->second;

	for (auto it = ref.begin(); it != ref.end(); it++)
	{
		//monsterCid = it->first;
		NPCRefLocation loc = it->second;

		BEGIN_PROFILE("g_GetCreatureMgr()::CreateNpc");

		pNpc = g_GetCreatureMgr()->CreateNpc(loc.m_id, sceneId, loc.m_bornPos);
		if (pNpc)
		{
			loc.m_deadTime = 0;
			m_curNpcCids.insert(std::make_pair(pNpc->GetCid(), loc));
			LogDebugFmtPrint("the sceneId:%d create one npc cid:%lu", sceneId, pNpc->GetCid());
		}
		else
		{
			LogErrFmtPrint("the refresh scene:%d create npc failed", sceneId);
		}

		END_PROFILE();
	}

	ref.clear();
}

void SceneGenenalCreatureRef::Update(uint32_t sceneId, uint64_t tick)
{
	//uint32_t monsterCid = 0;
	Monster* pMonster = nullptr;

	for (mapMonsterIdToRefLocation::iterator it = m_deadMonsterCids.begin(); it != m_deadMonsterCids.end();)
	{
		//monsterCid = it->first;
		MonsterRefLocation loc = it->second;
		if (loc.m_deadTime + loc.m_internalTime < g_GetGlobalServerTime()->Tick())
		{
			BEGIN_PROFILE("g_GetCreatureMgr()::CreateMonster");
			Point3<float> curDir = Point3<float>(0,0,1);
			if (loc.m_dir != Point3<float>())
			{
				float rad = AngleToRadian(loc.m_dir.y);
				float x = sin(rad);
				float z = cos(rad);
				Point3<float> dir = Point3<float>(x,0, z);
				float length = dir.length();
				if (length != 0)
				{
					curDir = dir/ length;
				}
			}
			MonsCreateParam createParam;
			createParam.createType = EMonsCreateType_Map;
			createParam.createTypeVal = sceneId;
			pMonster = g_GetCreatureMgr()->CreateMonster(loc.m_id, sceneId, loc.m_bornPos, createParam, curDir, loc.m_RefLocIndex, nullptr, 0, loc.m_group);
			if (pMonster)
			{
				loc.m_deadTime = 0;
				m_curMonsterCids.insert(std::make_pair(pMonster->GetCid(), loc));
				LogDebugFmtPrint("the sceneId:%d create one monster cid:%d", sceneId, pMonster->GetCid());
			}
			else
			{
				LogErrFmtPrint("the refresh scene:%d create monster failed", sceneId);
			}
			it = m_deadMonsterCids.erase(it);
			END_PROFILE();
		}
		else
		{
			it++;
		}
	}

	//uint32_t monsterCid = 0;
	Npc* pNpc = nullptr;
	for (mapNpcIdToRefLocation::iterator it = m_deadNpcCids.begin(); it != m_deadNpcCids.end();)
	{
		//monsterCid = it->first;
		NPCRefLocation loc = it->second;
		if (loc.m_deadTime + loc.m_internalTime < g_GetGlobalServerTime()->Tick())
		{
			BEGIN_PROFILE("g_GetCreatureMgr()::CreateNpc");
			pNpc = g_GetCreatureMgr()->CreateNpc(loc.m_id, sceneId, loc.m_bornPos);
			if (pNpc)
			{
				loc.m_deadTime = 0;
				m_curNpcCids.insert(std::make_pair(pNpc->GetCid(), loc));
				LogDebugFmtPrint("the sceneId:%d create one npc cid:%lu", sceneId, pNpc->GetCid());
			}
			else
			{
				LogErrFmtPrint("the refresh scene:%d create npc failed", sceneId);
			}
			it = m_deadNpcCids.erase(it);
			END_PROFILE();
		}
		else
		{
			it++;
		}
	}
}


GeneralCreatureRefMgr::GeneralCreatureRefMgr()
{

}

GeneralCreatureRefMgr::~GeneralCreatureRefMgr()
{

}

bool GeneralCreatureRefMgr::Init()
{
	return true;
}

bool GeneralCreatureRefMgr::UnInit()
{
	SceneGenenalCreatureRef* pScene = nullptr;
	sceneRefCreatureMap::iterator it = m_curScene.begin();
	for (; it != m_curScene.end(); it++)
	{
		pScene = it->second;
		if (pScene)
		{
			pScene->UnInit();
		}
		it->second = nullptr;
		delete pScene;
		pScene = nullptr;
	}
	m_curScene.clear();
	return true;
}

bool GeneralCreatureRefMgr::InitSceneRef(uint32_t mapId, uint32_t sceneId)
{
	/*if (g_GetMapLocationCfg()->isExistMapId(mapId) == false)
	{
		//不是每一个地图都有怪物要刷新，so return true
		return true;
	}*/

	sceneRefCreatureMap::iterator it = m_curScene.find(sceneId);
	if (it != m_curScene.end())
	{
		LogErrFmtPrint("sceneId:%d is repeat", sceneId);
		return false;
	}

	SceneGenenalCreatureRef *pSceneRef = new SceneGenenalCreatureRef(sceneId);
	if (pSceneRef->Init() == false)
	{
		LogErrFmtPrint("new SceneGenenalCreatureRef failed");
		return false;
	}

	m_curScene.insert(std::make_pair(sceneId, pSceneRef));

	if (pSceneRef->InitMonsterRef(mapId, sceneId) == false)
	{
		return false;
	}
	
	if (pSceneRef->InitNpcRef(mapId, sceneId) == false)
	{
		return false;
	}
	if (pSceneRef->InitCollectRef(mapId,sceneId) == false)
	{
		return false;
	}

	return true;
}

bool GeneralCreatureRefMgr::UnInitSceneRef(uint32_t sceneId)
{
	sceneRefCreatureMap::iterator it = m_curScene.find(sceneId);
	if (it == m_curScene.end())
	{
		return true;
	}
	SceneGenenalCreatureRef *pSceneRef = it->second;
	it->second = nullptr;
	pSceneRef->UnInit();
	delete pSceneRef;
	pSceneRef = nullptr;
	m_curScene.erase(sceneId);
	return true;
}

void GeneralCreatureRefMgr::UpdateNpcTeamDead(uint32_t sceneId, uint64_t tick, uint32_t npcTeamId)
{
	sceneRefCreatureMap::iterator sceneIt = m_curScene.find(sceneId);
	if (sceneIt == m_curScene.end())
	{
		return;
	}

	SceneGenenalCreatureRef *pSceneRef = sceneIt->second;

	if (pSceneRef)
	{
		pSceneRef->UpdateNpcTeam(sceneId, tick, npcTeamId);
	}
}

void GeneralCreatureRefMgr::npcDead(uint32_t sceneId, CharIDType npcCid)
{
	sceneRefCreatureMap::iterator sceneIt = m_curScene.find(sceneId);
	if (sceneIt == m_curScene.end())
	{
		return;
	}

	SceneGenenalCreatureRef *pSceneRef = sceneIt->second;

	if (pSceneRef)
	{
		pSceneRef->npcDead(npcCid);
	}
}

void GeneralCreatureRefMgr::monsterDead(uint32_t sceneId, CharIDType monsterCid)
{
	sceneRefCreatureMap::iterator sceneIt = m_curScene.find(sceneId);
	if (sceneIt == m_curScene.end())
	{
		return;
	}

	SceneGenenalCreatureRef *pSceneRef = sceneIt->second;

	if (pSceneRef)
	{
		pSceneRef->monsterDead(monsterCid);
	}
}

bool GeneralCreatureRefMgr::Update(uint64_t tick)
{
	sceneRefCreatureMap::iterator sceneIt = m_curScene.begin();
	uint32_t sceneId = 0;
	SceneGenenalCreatureRef *pSceneRef = nullptr;
	for (; sceneIt != m_curScene.end(); sceneIt++)
	{
		sceneId = sceneIt->first;
		pSceneRef = sceneIt->second;
		if (pSceneRef)
		{
			pSceneRef->Update(sceneId, tick);
		}
	}
	return true;
}
